/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
  * All rights reserved.</center></h2>
  *
  * This software component is licensed by ST under BSD 3-Clause license,
  * the "License"; You may not use this file except in compliance with the
  * License. You may obtain a copy of the License at:
  *                        opensource.org/licenses/BSD-3-Clause
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "bldc.h"
#include "led.h"
#include "bsp.h"

enum
{
    CTRL_MODE_NONE = 0,
    CTRL_MODE_UART,
    CTRL_MODE_RC,
    CTRL_MODE_CAN,
    CTRL_MODE_IO
};

#define CTRL_MODE_SET CTRL_MODE_RC
#define SIGNAL_LOST_TIME    500

#define DEBUG_MODE 1

uint16_t pwm_receive = 0;
uint16_t pwm_output=0;
uint32_t count_1s=0;

uint16_t signal_lost_count;
uint8_t output_enable = 0;//输出使能，当堵转 过流 没有输入 等情况 禁止输出

uint8_t state_update_wait = 0;	//串口上报状态等待
UPDATE_STATE_T update_state_data;
uint32_t convert_count = 0;

uint16_t pwm_input_up_time;
uint16_t pwm_input_dowm_time;
uint16_t pwm_input_value;

/*
	When current more than 15A for 100ms, enter over current protect
	when current more than 8A for 5s, enter over load protect

	if over current, stop output for 5s
	if over load, output change to half, exit after 1s
*/

#define OVER_CURRENT_TIME 100	//100ms
#define OVER_CURRENT_STOP_TIME	5000	//5second
#define OVER_CURRENT_VALUE	15000	//15A 

#define OVER_LOAD_TIME	5000	//5second
#define OVER_LOAD_EXIT_TIME	1000 //1second
#define OVER_LOAD_VALUE 8000	//8A

uint8_t over_load_flag = 0;
uint16_t over_load_count = 0;
uint8_t over_current_flag = 0;
uint32_t over_current_count = 0;

/*
	Debug
*/
uint8_t debug_force_run_enable = 0;//仿真时 手动写1 启动强制转动


/**
 * @brief GPIO中断
 */
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{	
	int i=0;
	uint8_t state;
	
	/* Hall Input */
	if((GPIO_Pin == HALL1_PIN)||(GPIO_Pin == HALL2_PIN)||(GPIO_Pin == HALL3_PIN))
	{
        hall = hall_get_position();
		
        bldc_hall_change_callback();

		for(i=0;i<5;i++)
		{
			update_state_data.hall_step[i] = update_state_data.hall_step[i+1];
		}
		
		update_state_data.hall_step[5] = hall;
        convert_count++;
		
		if(GPIO_Pin == HALL1_PIN)
		{
			state = HAL_GPIO_ReadPin(HALL1_PORT, HALL1_PIN);
			if(state)
			{
				led_on();
			}
			else
			{
				led_off();
			}
			HAL_GPIO_WritePin(SPEED_PORT, SPEED_PIN, state);
		}
	}
}

/**
 * @brief 定时器4捕获中断
 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == TIM4)
    {
        if(HAL_GPIO_ReadPin(PWM_PORT,PWM_PIN)==GPIO_PIN_SET)
        {
            pwm_input_up_time = TIM4->CCR1;
            
            __HAL_TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_FALLING);
        }
        else
        {
            pwm_input_dowm_time = TIM4->CCR1;
            
            if(pwm_input_dowm_time > pwm_input_up_time)
            {
                pwm_input_value = pwm_input_dowm_time - pwm_input_up_time;
            }
            else
            {
                pwm_input_value = 65535 + pwm_input_dowm_time - pwm_input_up_time;
            }
            
            __HAL_TIM_SET_CAPTUREPOLARITY(&htim4,TIM_CHANNEL_1,TIM_INPUTCHANNELPOLARITY_RISING);
            
            if(pwm_input_value > 500 && pwm_input_value < 2500)
            {
                if(pwm_input_value < 1000)
                {
                    pwm_input_value = 1000;
                }
                if(pwm_input_value > 2000)
                {
                    pwm_input_value = 2000;
                }
                
                pwm_input = pwm_input_value;
                pwm_input_done = 1;
            }
        }
    }
}

/**
 * @brief 定时器3定时中断 定时器3用于pwm输出
 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance == TIM3)
	{
		if(debug_force_run_enable==0)
		{
			bldc_convert(pwm_output);  
		}
	}
}

void systick_callback(void)
{
	led_pool();	
    bldc_timer_callback();   
    
    count_1s++;

    if(count_1s>1000)
    {
        count_1s = 0;

        update_state_data.speed = convert_count;
        convert_count = 0;
    }
	
	HAL_ADC_Start_IT(&hadc1);
	HAL_ADC_Start_IT(&hadc2);    
    
    if(signal_lost_count > 0)
    {
        signal_lost_count --;
    }

	if(state_update_wait > 0)
	{
		state_update_wait --;
	}

	/* Over current and load protect */
	/* current more than OVER_CURRENT_VALUE for OVER_CURRENT_TIME, enter protect */
	if(current > OVER_CURRENT_VALUE) {
		if(over_current_flag == 0) {
			over_current_count++;
			if(over_current_count>OVER_CURRENT_TIME) {
				over_current_flag = 1;
				over_current_count = OVER_CURRENT_STOP_TIME;
			}
		}
	}
	else {
		if(over_current_flag == 0) {
			over_current_count = 0;
		}
		else {
			/* wait stop time and exit over current */
			if(over_current_count > 0) {
				over_current_count --;
			}
			else {
				over_current_flag = 0;
			}
		}
	}
	
	if(current > OVER_LOAD_VALUE) {
		if(over_load_flag==0) {
			over_load_count++;
			if(over_load_count > OVER_LOAD_TIME) {
				over_load_flag = 1;
				over_load_count = OVER_LOAD_EXIT_TIME;
			}
		}
	}
	else {
		if(over_load_flag==0) {
			over_load_count = 0;
		}
		else {
			if(over_load_count > 0) {
				over_load_count--;
			}
			else {
				over_load_flag = 0;
			}
		}
	}
}

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
	HAL_Init();

	SystemClock_Config();
    
    MX_GPIO_Init();
	MX_ADC1_Init();
	MX_ADC2_Init();
    MX_USART2_UART_Init(9600);
	MX_CAN_Init();

	MX_TIM3_Init();
	MX_TIM4_Init();
    
    HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_3);
	HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_4);

	output_zero();
	
    HAL_TIM_IC_Start_IT(&htim4,TIM_CHANNEL_1);
	
	HAL_ADCEx_Calibration_Start(&hadc1); 
	HAL_ADCEx_Calibration_Start(&hadc2); 	
    
#if DEBUG_MODE == 0
    MX_IWDG_Init();
#endif

	while (1)
	{          
        switch(CTRL_MODE_SET)
        {
            case CTRL_MODE_UART:				
				if(uart_ctrl_flag)
				{
					uart_ctrl_flag = 0;
					signal_lost_count = SIGNAL_LOST_TIME;
				}
						
                direction = uart_ctrl_dir;
                pwm_receive = uart_ctrl_pwm * 10;
                break;
            case CTRL_MODE_CAN:
                break;
            case CTRL_MODE_RC:
				if(pwm_input_done)
				{
					pwm_input_done = 0; 
					signal_lost_count = SIGNAL_LOST_TIME;
				}
		
//                if(pwm_input<1450) //反转
//                {
//                    direction = DIR_CCW;
//                    pwm_receive = (1500 - pwm_input)*2;
//                }
//                else if( pwm_input<1550) //停止
//                {
//                    pwm_receive = 0;
//                }
//                else if(pwm_input<=2000) //正转
//                {
//                    direction = DIR_CW;
//                    pwm_receive = (pwm_input-1500)*2;
//                }
				if(pwm_input > 1000 && pwm_input < 2000)
				{
					pwm_receive = pwm_input-1000;
				}
                else	//错误
                {
                    pwm_receive = 0;
                }
                break;
            case CTRL_MODE_IO:
                break;
            default:
                break;
        }       
		
		/* 丢失控制信号超时，关闭输出 */
        if(signal_lost_count==0)
        {
			pwm_receive = 0;	
        }

		/* calc output */
		if(over_current_flag)	//过流保护 立刻停止输出
		{
			pwm_output = 0;
			output_zero();
		}
		else if(over_load_flag)	//过载保护 输出降低一半
		{
			pwm_output = pwm_receive / 2;
		}
		else					//Normal
		{
			pwm_output = pwm_receive;  			
		}        
        
        if(last_hall != hall)
        {
            last_hall = hall;
        }         
		
		/* 调试模式 强制转动 */
		if(debug_force_run_enable)
		{
			force_run();
		}

		/* update state */
		if(state_update_wait==0)
		{
			state_update_wait = 100;

			update_state_data.vbus = vbus;
			update_state_data.current = current;
			//update_state.speed = 0;
			update_state_data.over_current = over_current_flag;
			update_state_data.over_load = over_load_flag;
			cmd_state_send(update_state_data);
		}
		
#if DEBUG_MODE == 0
		MX_IWDG_Refresh();   
#endif
             
	}
}/*main*/



/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */

  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{ 
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
